package MathCore;

import java.util.Enumeration;
import java.util.Stack;
import MathCore.Operands.*;
import MathCore.Operators.*;
import MathCore.Renders.Atom;
import MathCore.Renders.Block;
import MathCore.Renders.Stripe;

public class RaSysT extends Object
{
	public static final int TYPE_FUNCTION = 0, TYPE_OPERATOR = 1;
	public static final int NONE = 0, SIMPLE_BRACKET=1, LIST_BRACKET=2, POINT=3;

	private int preferType = TYPE_FUNCTION;
	private int open = SIMPLE_BRACKET;
	private int close = NONE;
	private boolean numberBefore;

	public RaSysT()
	{
	}

	public int closed()
	{
		return close;
	}

	public int opened()
	{
		return open;
	}

	public int type()
	{
		return preferType;
	}

	public boolean canInputVar()
	{
		return numberBefore;
	}

	public void process(Stripe ex, Block block)
	{
		if(block == null || ex.empty())
		{
			preferType = TYPE_FUNCTION;
			open = SIMPLE_BRACKET;
			close = NONE;
			numberBefore = false;

			return;
		}

		// определить рекомендуемый тип
		if(block instanceof Atom)
		{
			Lexeme lex = ((Atom)block).lex();
			if(lex instanceof Variable) preferType = TYPE_OPERATOR;
			else if(lex instanceof Number || lex instanceof Constant) preferType = TYPE_OPERATOR;
			else if(lex instanceof Symbol)
			{
				Symbol s = (Symbol) lex;
				if(s.getType() == Symbol.RIGHT_BRACE || s.getType() == Symbol.RIGHT_LIST) preferType = TYPE_OPERATOR;
				else preferType = TYPE_FUNCTION;
			}
			else preferType = TYPE_FUNCTION;
		}
		else
		{
			preferType = TYPE_OPERATOR;
		}

		// определить открываемую лексему
		if(block instanceof Atom)
		{
			Lexeme lex = ((Atom)block).lex();
			if(lex instanceof Number && ((Number)lex).numbers_after_point == 0)
			{
				open = POINT;
			}
			else if(lex instanceof Operator)
			{
				open = SIMPLE_BRACKET;
			}
			else if(lex instanceof Symbol &&
					( ((Symbol)lex).getType() == Symbol.LEFT_BRACE ||
					  ((Symbol)lex).getType() == Symbol.COMMA      ||
					  ((Symbol)lex).getType() == Symbol.LEFT_LIST)    )
			{
				open = SIMPLE_BRACKET;
			}
			else
			{
				open = NONE;
			}
		}
		else open = NONE;

		// определить закрываемую лексему
		Stack braces = new Stack();
		Block b;
		Lexeme l;
		Symbol s;
		for (b = ex.first(); b != null; b = b.next)
		{
			if(b instanceof Atom)
			{
				if(((Atom)b).lex() instanceof Symbol)
				{
					s = (Symbol) ((Atom)b).lex();

					switch(s.getType())
					{
						case Symbol.LEFT_BRACE:
						case Symbol.LEFT_LIST:
							braces.push(s);
							break;

						case Symbol.RIGHT_BRACE:
							if(!braces.empty())
							{
								Symbol s2 = (Symbol) braces.lastElement();
								if(s2.getType() == Symbol.LEFT_BRACE) braces.pop();
							}
							break;

						case Symbol.RIGHT_LIST:
							if(!braces.empty())
							{
								Symbol s2 = (Symbol) braces.lastElement();
								if(s2.getType() == Symbol.LEFT_LIST) braces.pop();
							}
							break;
					}
				}
			}
				//if(block instanceof Atom)
			if(block == b)
			{
				if(braces.empty()) close = NONE;
				else
				{
					Symbol s2 = (Symbol) braces.pop();
					if(s2.getType() == Symbol.LEFT_BRACE) close = SIMPLE_BRACKET;
					else close = LIST_BRACKET;
				}

				break;
			}
			
		}

		numberBefore = true;
	}

	public void process(Expression ex, Lexeme lex)
	{
		if(lex == null || ex.empty())
		{
			preferType = TYPE_FUNCTION;
			open = SIMPLE_BRACKET;
			close = NONE;
			numberBefore = false;

			return;
		}

		// определить рекомендуемый тип
		if(lex instanceof Variable) preferType = TYPE_OPERATOR;
		else if(lex instanceof Number) preferType = TYPE_OPERATOR;
		else if(lex instanceof Symbol)
		{
			Symbol s = (Symbol) lex;
			if(s.getType() == Symbol.RIGHT_BRACE || s.getType() == Symbol.RIGHT_LIST) preferType = TYPE_OPERATOR;
			else preferType = TYPE_FUNCTION;
		}
		else preferType = TYPE_FUNCTION;

		// определить открываемую лексему
		if(lex instanceof Number && ((Number)lex).numbers_after_point == 0)
		{
			open = POINT;
		}
		else if(lex instanceof Operator)
		{
			open = SIMPLE_BRACKET;
		}
		else if(lex instanceof Symbol &&
				( ((Symbol)lex).getType() == Symbol.LEFT_BRACE ||
				  ((Symbol)lex).getType() == Symbol.COMMA      ||
				  ((Symbol)lex).getType() == Symbol.LEFT_LIST)    )
		{
			open = SIMPLE_BRACKET;
		}
		else
		{
			open = NONE;
		}

		// определить закрываемую лексему
		Stack braces = new Stack();
		Lexeme l;
		Symbol s;
		for (l = ex.first(); l != null; l = l.next)
		{
			if(l instanceof Symbol)
			{
				s = (Symbol) l;

				switch(s.getType())
				{
					case Symbol.LEFT_BRACE:
					case Symbol.LEFT_LIST:
						braces.push(s);
						break;

					case Symbol.RIGHT_BRACE:
						if(!braces.empty())
						{
							Symbol s2 = (Symbol) braces.lastElement();
							if(s2.getType() == Symbol.LEFT_BRACE) braces.pop();
						}
						break;

					case Symbol.RIGHT_LIST:
						if(!braces.empty())
						{
							Symbol s2 = (Symbol) braces.lastElement();
							if(s2.getType() == Symbol.LEFT_LIST) braces.pop();
						}
						break;
				}
			}

			if(l == lex)
			{
				if(braces.empty()) close = NONE;
				else
				{
					Symbol s2 = (Symbol) braces.pop();
					if(s2.getType() == Symbol.LEFT_BRACE) close = SIMPLE_BRACKET;
					else close = LIST_BRACKET;
				}

				break;
			}
		}

		// определить число ли
		numberBefore = lex instanceof Number;
	}
}
